package com.gdc.miaosha.config;

import cn.hutool.core.util.ArrayUtil;
import com.alibaba.fastjson.JSON;
import com.gdc.miaosha.constants.CommonConstant;
import com.gdc.miaosha.constants.RedisConstant;
import com.gdc.miaosha.entity.User;
import com.gdc.miaosha.result.CodeMsg;
import com.gdc.miaosha.result.Result;
import com.gdc.miaosha.service.IUserService;
import com.gdc.miaosha.util.RedisUtil;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.util.Objects;

/**
 * 访问限制拦截器
 */
@Component
public class AccessInterceptor extends HandlerInterceptorAdapter {
	
	@Autowired
	private IUserService userService;
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		if(handler instanceof HandlerMethod) {
			User user = getUser(request);
			UserContext.setUser(user);

			// 获取处理的方法
			HandlerMethod handlerMethod = (HandlerMethod)handler;
			// 查看是否存在注解
			AccessLimit accessLimit = handlerMethod.getMethodAnnotation(AccessLimit.class);
			if(accessLimit == null) {
				return true;
			}
			int seconds = accessLimit.seconds() > 0 ? accessLimit.seconds() : 5;
			int maxCount = accessLimit.maxCount();
			String reqUri = request.getRequestURI();
			if(accessLimit.needLogin()) {
				if(user == null) {
					render(response, CodeMsg.SESSION_ERROR);
					return false;
				}
				reqUri += "_" + user.getId();
			}
			Integer count = RedisUtil.get(RedisConstant.ACCESS_LIMIT + reqUri, Integer.class);
	    	if(count  == null) {
				RedisUtil.set(RedisConstant.ACCESS_LIMIT + reqUri, 1, seconds);
	    	}else if(count < maxCount) {
				RedisUtil.incr(RedisConstant.ACCESS_LIMIT + reqUri, 1);
	    	}else {
	    		render(response, CodeMsg.ACCESS_LIMIT_REACHED);
	    		return false;
	    	}
		}
		return true;
	}
	
	private void render(HttpServletResponse response, CodeMsg cm)throws Exception {
		response.setContentType("application/json;charset=UTF-8");
		OutputStream out = response.getOutputStream();
		String str  = JSON.toJSONString(Result.error(cm));
		out.write(str.getBytes("UTF-8"));
		out.flush();
		out.close();
	}

	private User getUser(HttpServletRequest request) {
		if (ArrayUtil.isEmpty(request.getCookies())) {
			return null;
		}
		String token = Lists.newArrayList(request.getCookies()).stream()
				.filter(cookie -> Objects.equals(cookie.getName(), CommonConstant.COOKIE_KEY))
				.map(Cookie::getValue)
				.findFirst()
				.orElse(null);
		return userService.getByToken(token);
	}
	
}
